-- Radical by Basil Voronkov
-- Module 'core'
---------------------------------------------
-- Core functions that are used by other modules,
-- including eval and application functions.
require "lib/const"

function nvl(x,y)
  if x == nil then
    return y;
  else
    return x;
  end
end

function apply(c)
  return assert(loadstring("return ("..c..")"))();
end

function exec(s)
  assert(loadstring(s))();
end

function is_table(o)
  return type(o) == "table";
end

function is_function(o)
  return type(o) == "function";
end

function is_string(o)
  return type(o) == "string";
end

function rcall(o,s)
  if o == nil then
    return nil;
  elseif is_function(o) then
    return rcall(o(s), s);
  else
    return o;
  end
end

function deref_if(o)
  if is_table(o) then
    return deref(o);
  else
    return o;
  end
end

function ref_if(o)
  if is_string(o) then
    return ref(o);
  else
    return o;
  end
end

function copy_attr(src, dst)
  for k,v in pairs(src) do
    if dst[k] == nil then
      dst[k] = v;
    end
  end
end

function notnil(o,nm)
  if o == nil then
    error("Error: "..nm.." is nil."..debug.traceback ());
  end
end

function raise(err)
  if err == nil then
    err = "";
  end
  error(err.."\n"..debug.traceback());
end

function play_music(file,loop,fadeout,fadein)
  local fl = file;
  local fout,fin = 2000,2000;
  if file ~= nil and file ~= "" then
    fl = const.path.mus..file..".ogg";
  end
  if fadeout ~= nil then    
    fout = fadeout;
  end
  if fadein ~= nil then
    fin = fadein;
  end
  set_music_fading(fadeout, fadein);
  if loop == nil then
    loop = 1;
  end
  if fl ~= nil then
    set_music(fl, loop);
  else
    stop_music();
    mute_sound();
    _lastsound = nil;
  end
end

function play_sound(file,loop,ch)
  notnil(file,"file");
  local fl = const.path.sfx..file..".ogg";
  if ch == nil then
    ch = 2;
  end
  set_sound(fl, ch, loop);
  if loop ~= nil then
    _lastsound = {file,loop,ch};
  end
end

function mute_sound()
  stop_sound(2);
  stop_sound(3);
  stop_sound(4);
end

function map(mx, my, mw, mh)
  return {
     items_     = {}
    ,add        = function(s, key, x, y, w, h)
                    s.items_[key] = {x,y,w,h};
                  end
    ,remove     = function(s,...)
                    for i,v in ipairs(arg) do
                      s.items_[v] = nil;
                    end
                  end
    ,get        = function(s, x, y)
                    if x == nil or y == nil then
                      return nil;
                    end
                    x = x - mx;
                    y = y - my;
                    if x < 0 or y < 0 or x > mw or y > mh then
                      return nil;
                    else
                      for i,v in pairs(s.items_) do
                        if
                              x >= v[1]
                          and x <= v[1] + v[3]
                          and y >= v[2]
                          and y <= v[2] + v[4]
                        then
                          return i;
                        end
                      end
                    end
                    return nil;
                  end
  }
end

function set_checkpoint()
  make_snapshot(1);
  prefs["last_episode"] = "$checkpoint$";
end

function load_checkpoint()
	restore_snapshot(1);
end
